#pragma once

/*
 * pipe module class.
 */
#include <memory>
#include "pipe_config.h"
#include "include/pipe.h"
#include "all.hpp"
#include "main_service.h"
#include "pipe_session.h"
#include "default_interface.hpp"
#include "service_discovery.h"

namespace anet {
	namespace pipe {
		// anet type.
		using sharePtrSession = anet::tcp::CSharePtrSession<CPipeSession>;
		using userSessionFactory = anet::tcp::CSharePtrSessionFactory<CPipeSession>;

		// service discovery type.
		using serviceDiscoveryEntity = anet::ServiceDiscoverySpace::ServiceEntityInfo;
		using serviceDiscoveryType = anet::ServiceDiscoverySpace::ServiceDiscovery;
		using serviceDiscoveryUniquePtrType = std::unique_ptr<serviceDiscoveryType>;
		using serviceDiscoveryFunc = anet::ServiceDiscoverySpace::newServiceDiscoveryFunc;

		// timer type.
		using timeWheelType = STimeWheelSpace::CTimeWheel;

		class CPipeModule final : public IPipeModule {
		protected:
			CPipeModule();
			virtual ~CPipeModule();
			CPipeModule(const CPipeModule& rhs) = delete;
			CPipeModule& operator=(const CPipeModule& rhs) = delete;

		public:
			static CPipeModule& instance();
			
		public:
			// init initializes the config and pipe reporter interface
			virtual bool Init(const char* pipePath, IPipeReporter* reporter) override;

			// Run the pipe module for anet net and timer.
			// !!you can ignore it if your project can do it.
			virtual bool Run(int count) override;

			// get local pipe id and name.
			virtual unsigned int GetLocalId() const override;
			virtual const std::string& GetLocalName() const override;

			// get reporter.
			virtual IPipeReporter* GetReporter() override;

		public:
			// timer.
			timeWheelType& GetTimeWheel();

			// get session factory.
			userSessionFactory* GetSessionFactory();

			// connection token check.
			bool CheckConnectInfo(const std::string &name, const std::string &token);

			// remove service name.
			void RemoveService(const std::string& name);

			// config pointer.
			CPipeConfig* GetPipeConfig();

		protected:
			// new service discovery callback.
			bool onNewServiceDiscovery(const serviceDiscoveryEntity* node);

			// start pipe module.
			bool start(IPipeReporter* reporter);

			// initialize service discovery to connect some servers.
			bool initServiceDiscovery();
			
		private:
			// pipe config.
			CPipeConfig m_pipeConfig;

			// anet tcp event loop.
			anet::tcp::CEventLoop m_loop{ 1 };

			// anet tcp server.
			anet::tcp::CServer m_server;

			// anet tcp session factory.
			userSessionFactory m_sessionFactory;

			// anet tcp packet codec.
			anet::tcp::CBigCodec m_codec;

			// pipe report callback.
			IPipeReporter* m_pipeReporter{ nullptr };

			// time wheel module.
			timeWheelType m_timeWheel;

			// service discovery module.
			serviceDiscoveryUniquePtrType m_serviceDiscovery{ nullptr };
		};
	}
}